package com.yeskery.nut.util;

import com.yeskery.nut.core.InputStreamResource;
import com.yeskery.nut.core.MediaType;
import com.yeskery.nut.core.NutException;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Base64图片处理工具类
 * @author YESKERY
 * 2024/8/13
 */
public class Base64ImageUtils {

    /** scheme到扩展url对照map */
    private static final Map<String, String> SCHEME_EXTENSION_MAP = new HashMap<>(8);

    /** 扩展url到scheme对照map */
    private static final Map<String, String> EXTENSION_SCHEME_MAP = new HashMap<>(8);

    /** 支持的媒体类型集合 */
    private static final Set<MediaType> SUPPORT_MEDIA_TYPE_SET = new HashSet<>(8);

    static {
        addScheme(MediaType.IMAGE_JPEG);
        addScheme(MediaType.IMAGE_PNG);
        addScheme(MediaType.IMAGE_GIF);
        addScheme(MediaType.IMAGE_X_ICON);
        SUPPORT_MEDIA_TYPE_SET.add(MediaType.IMAGE_JPEG);
        SUPPORT_MEDIA_TYPE_SET.add(MediaType.IMAGE_PNG);
        SUPPORT_MEDIA_TYPE_SET.add(MediaType.IMAGE_GIF);
        SUPPORT_MEDIA_TYPE_SET.add(MediaType.IMAGE_X_ICON);
    }

    /**
     * 私有化构造方法
     */
    private Base64ImageUtils() {
    }

    /**
     * 将图片转换为Base64格式
     * @param postfix 后缀名
     * @param imageBytes 图片字节
     * @param appendDataURLScheme 是否添加图片url Scheme
     * @return Base64格式图片
     */
    public static String imageToBase64(String postfix, byte[] imageBytes, boolean appendDataURLScheme) {
        return imageToBase64(MediaType.getMediaTypeByPostfix(postfix), imageBytes, appendDataURLScheme);
    }

    /**
     * 将图片转换为Base64格式
     * @param postfix 后缀名
     * @param imageBytes 图片字节
     * @return Base64格式图片
     */
    public static String imageToBase64(String postfix, byte[] imageBytes) {
        return imageToBase64(postfix, imageBytes, true);
    }

    /**
     * 将图片转换为Base64格式
     * @param postfix 后缀名
     * @param inputStream 图片输入流
     * @param appendDataURLScheme 是否添加图片url Scheme
     * @return Base64格式图片
     */
    public static String imageToBase64(String postfix, InputStream inputStream, boolean appendDataURLScheme) {
        return imageToBase64(postfix, IOUtils.readByteArray(inputStream), appendDataURLScheme);
    }

    /**
     * 将图片转换为Base64格式
     * @param postfix 后缀名
     * @param inputStream 图片输入流
     * @return Base64格式图片
     */
    public static String imageToBase64(String postfix, InputStream inputStream) {
        return imageToBase64(postfix, inputStream, true);
    }

    /**
     * 将图片转换为Base64格式
     * @param mediaType 媒体类型
     * @param imageBytes 图片字节
     * @param appendDataURLScheme 是否添加图片url Scheme
     * @return Base64格式图片
     */
    public static String imageToBase64(MediaType mediaType, byte[] imageBytes, boolean appendDataURLScheme) {
        if (!SUPPORT_MEDIA_TYPE_SET.contains(mediaType)) {
            throw new NutException("UnSupport MediaType[" + mediaType + "].");
        }
        String imageBase64 = new String(Base64.getEncoder().encode(imageBytes), StandardCharsets.UTF_8);
        if (appendDataURLScheme) {
            imageBase64 = EXTENSION_SCHEME_MAP.get(mediaType.getPostfix()[0]) + imageBase64;
        }
        return imageBase64;
    }

    /**
     * 将图片转换为Base64格式
     * @param mediaType 媒体类型
     * @param imageBytes 图片字节
     * @return Base64格式图片
     */
    public static String imageToBase64(MediaType mediaType, byte[] imageBytes) {
        return imageToBase64(mediaType, imageBytes, true);
    }

    /**
     * 将图片转换为Base64格式
     * @param mediaType 媒体类型
     * @param inputStream 图片输入流
     * @param appendDataURLScheme 是否添加图片url Scheme
     * @return Base64格式图片
     */
    public static String imageToBase64(MediaType mediaType, InputStream inputStream, boolean appendDataURLScheme) {
        return imageToBase64(mediaType, IOUtils.readByteArray(inputStream), appendDataURLScheme);
    }

    /**
     * 将图片转换为Base64格式
     * @param mediaType 媒体类型
     * @param inputStream 图片输入流
     * @return Base64格式图片
     */
    public static String imageToBase64(MediaType mediaType, InputStream inputStream) {
        return imageToBase64(mediaType, inputStream, true);
    }

    /**
     * 将Base64格式图片转换为字节数组
     * @param imageBase64 Base64格式图片
     * @return 转换后的为字节数组
     */
    public static byte[] base64ToImageArray(String imageBase64) {
        int index = imageBase64.indexOf(",");
        if (index >= 0) {
            imageBase64 = imageBase64.substring(index + 1);
        }
        return Base64.getDecoder().decode(imageBase64);
    }

    /**
     * 将Base64格式图片转换为输入流
     * @param imageBase64 Base64格式图片
     * @return 转换后的为输入流
     */
    public static InputStream base64ToImageInputStream(String imageBase64) {
        return new ByteArrayInputStream(base64ToImageArray(imageBase64));
    }

    /**
     * 将Base64格式图片转换为输入流资源对象
     * @param imageBase64 Base64格式图片
     * @return 转换后的输入流资源对象
     */
    public static InputStreamResource base64ToImageInputStreamResource(String imageBase64) {
        return () -> base64ToImageInputStream(imageBase64);
    }

    /**
     * 添加scheme
     * @param mediaType 媒体类型
     */
    private static void addScheme(MediaType mediaType) {
        String dataUrl = "data:" + mediaType.getValue() + ";base64,";
        for (String postfix : mediaType.getPostfix()) {
            SCHEME_EXTENSION_MAP.put(dataUrl, postfix);
            EXTENSION_SCHEME_MAP.put(postfix, dataUrl);
        }
    }
}
